﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using App.Common;
using App.Web.ViewModels;
using Microsoft.Owin.Security;
using Abp.Threading;
using Abp.Runtime.Security;
using System.Globalization;
using App.Authorization.Users;
using static App.Authorization.Users.UserManager;
using App.Authorization;
using Abp.Configuration.Startup;

namespace App.Web.Controllers
{
    public class AccountController : AppMvcControllerBase
    {
        private readonly UserManager _userManager;
        private readonly LoginResultTypeHelper _loginResultTypeHelper;
        private readonly IMultiTenancyConfig _multiTenancyConfig;

        public AccountController(UserManager userManager, 
            LoginResultTypeHelper loginResultTypeHelper,
            IMultiTenancyConfig multiTenancyConfig)
        {
            _userManager = userManager;
            _loginResultTypeHelper = loginResultTypeHelper;
            _multiTenancyConfig = multiTenancyConfig;
        }

        public ActionResult Login(string returnUrl)
        {
            ViewBag.ReturnUrl = returnUrl;
            ViewBag.IsMultiTenancyEnabled = _multiTenancyConfig.IsEnabled;

            return View();
        }

        // POST: /Account/Login
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Login(LoginViewModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                var loginResult = AsyncHelper.RunSync(() => ValidateUserName(model.UserName,model.Password, model.TenancyName)); 
                if (loginResult.Result ==  LoginResultType.Success)
                {
                    var authentication = HttpContext.GetOwinContext().Authentication;

                    var claims = new List<Claim> { new Claim(ClaimsIdentity.DefaultNameClaimType, model.UserName) };
                    claims.AddRange(loginResult.Roles.Select(role => new Claim(ClaimTypes.Role, role)));
                    claims.Add(new Claim(ClaimTypes.NameIdentifier, loginResult.UserId.ToString()));
                    if (loginResult.TenantId.HasValue)
                    {
                        claims.Add(new Claim(AbpClaimTypes.TenantId, loginResult.TenantId.Value.ToString(CultureInfo.InvariantCulture)));
                    }

                    authentication.SignIn(
                        new AuthenticationProperties { IsPersistent = model.RememberMe },
                        new ClaimsIdentity(claims, "ApplicationCookie")
                    );

                    return RedirectToLocal(returnUrl);
                }

                var message = _loginResultTypeHelper.CreateExceptionForFailedLoginAttempt(loginResult.Result, model.UserName, model.TenancyName);

                ModelState.AddModelError(String.Empty, message);
            }

            ViewBag.ReturnUrl = returnUrl;
            ViewBag.IsMultiTenancyEnabled = _multiTenancyConfig.IsEnabled;

            return View(model);
        }

        public ActionResult LogOff()
        {
            var authentication = HttpContext.GetOwinContext().Authentication;
            authentication.SignOut();

            return Redirect("/account/login?ReturnUrl="+Request["returnUrl"]);
        }

        #region helpers
        public async Task<LoginResult> ValidateUserName(string userName,string password, string tenancyName)
        {
            return await _userManager.LoginAsync(userName, password, tenancyName);
        }

        private ActionResult RedirectToLocal(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("index", "home");
            }
        }
        #endregion
    }
}